#!/usr/bin/env python
# encoding: utf-8


"""
@file: jieti.py
@time: 2016/10/21 下午2:42
"""
# 解题
from mathsolver.functions.base import *
from mathsolver.functions.sanjiao import Jiao as jiao
from sympy import expand_trig, sin, cos, tan, cot, pi, degree, trigsimp, solveset
from mathsolver.functions.sanjiao import sanjiao_utils as su
from mathsolver.functions.sanjiao import hanshu as hu
from mathsolver.functions.budengshi import common_opers as co
from mathsolver.functions.sanjiao.huajian import trig_simplify


# 若sin(x+\\frac{π}{6})=\\frac{4}{5},则cos(x-\\frac{π}{3})=().
class SanJiaoHanShu001(BaseFunction):
    def solver(self, *args):
        t_sineq = args[0].value
        t1, t1_value = su.trig_eq_std(BaseEq([t_sineq, 0])).sympify()
        t2 = args[1].value
        expand_t1 = expand_trig(t1)
        expand_t2 = expand_trig(t2)
        self.steps.append([r'\because %s = %s' % (new_latex(t1), new_latex(expand_t1)), ''])
        t1_dict = su.trig_coefficients_dict(expand_t1)
        temp_trig_t = sympify('1')
        for k, v in t1_dict.items():
            if not k.is_real:
                temp_trig_t = k
                break
        t1_dict = dict(map(lambda d: (str(d[0]), d[1]), t1_dict.items()))
        t2_dict = su.trig_coefficients_dict(expand_t2)
        t2_dict = dict(map(lambda d: (str(d[0]), d[1]), t2_dict.items()))
        temp_trig_t = str(temp_trig_t)
        ratio = t1_dict[temp_trig_t] / t2_dict[temp_trig_t]
        t2_value = t1_value / ratio
        self.steps.append([r'\therefore %s = %s' % (new_latex(t2), new_latex(expand_t2)), ' = ' + new_latex(t2_value)])
        self.output.append(BaseNumber(t2_value))
        return self


# 化简:\\frac{sin(π-α)sin(3π-α)+sin(-α-π)sin(α-2π)}{sin(4π-α)sin(5π+α)}
class SanJiaoHanShu002(BaseFunction):
    def solver(self, *args):
        poly = args[0].value
        simp_poly, step_list = su.trig_simp(poly)
        self.steps.append(['' + new_latex(poly), ''])
        for s in step_list:
            self.steps.append(['= ' + s, ''])
        self.steps.append(['= ' + new_latex(simp_poly), ''])
        self.output.append(BasePoly(simp_poly))
        self.label.add('三角函数化简')
        return self


# 函数y=tanx-cotx的最小正周期为().
class SanJiaoHanShu003(BaseFunction):
    @staticmethod
    def simp_ended(sinf):  # 是否已经达到化简的要求 就是形如 y = k*sin(w*x + b)+c
        sin_mons, _ = co.split_mons_const(sinf)
        if len(co.coefficients_dict(sin_mons)) > 1:
            return False
        coef = su.trig_coeff(sin_mons)
        trig_f = sin_mons / coef
        if type(trig_f) in (sin, cos, tan, cot):
            return True
        else:
            return False

    def solver(self, *args):
        if isinstance(args[0], BaseSinFunc):
            f = args[0].expression
        elif isinstance(args[0], BaseFunction):
            f = args[0].value['expression']
        elif isinstance(args[0], BaseEq):
            _, f = args[0].sympify()
        else:
            f = sympify(args[0])
        sim_f = trig_simplify(f)
        self.steps.append(['化简得 %s = %s' % (new_latex(f), new_latex(sim_f)), ' '])
        self.steps.append(['= ' + new_latex(sim_f), ''])
        t_c = hu.trig_cycle(sim_f)
        self.steps.append([r'\therefore ', ' 最小正周期为: ' + new_latex(t_c)])
        self.output.append(BaseNumber(t_c))
        self.label.add('三角函数最小正周期')
        # self.label.add('周期')
        return self


# 同角三角函数间基本关系--sinx/cosx/tanx三者之间相互求解
# sin(α+\\frac{π}{4})=\\frac{\\sqrt{2}}{4},则sinα=().
# 若tanα=-\\frac{1}{2},并,α是第二象限角,那么sinα的值为()
class SanJiaoHanShu004(BaseFunction):
    @staticmethod
    def std_simp_trig(f):
        f = sympify(f)
        l, r = su.trig_eq_std(BaseEq([f, '0'])).sympify()
        c = su.trig_coeff(l)
        n_l, n_r = l / c, r / c
        return BaseEq([n_l, n_r])

    def solver(self, *args):
        if isinstance(args[0], BaseEq):
            l, r = args[0].sympify()
            eq_f = l - r
        else:
            eq_f = sympify(args[0].value)
        t_f = sympify(args[1].value)
        text = args[-1]
        trig_type = 'tan'
        if isinstance(t_f, sin):
            t_k = 'A'
            trig_type = 'sin'
        elif isinstance(t_f, cos):
            t_k = 'C'
            trig_type = 'cos'
        std_eq = SanJiaoHanShu004.std_simp_trig(eq_f)
        self.steps.append([r'\because ', std_eq.printing()])
        trig_m, trig_v = std_eq.sympify()
        trig_arg = su.trig_arg(trig_m)
        formulas = BaseEqs(
            [[tan(trig_arg), sin(trig_arg) / cos(trig_arg)], [sin(trig_arg) ** 2 + cos(trig_arg) ** 2, '1']])
        self.steps.append([formulas.printing(), ''])
        if isinstance(trig_m, sin):
            d = hu.trig_der('A', trig_v)
        elif isinstance(trig_m, cos):
            d = hu.trig_der('C', trig_v)
        elif isinstance(trig_m, tan):
            d = hu.trig_der('T', trig_v)
        t_vs = d[t_k]
        quad_text = ''
        if text.find('第一象限') >= 0:
            pm = jiao.trig_f_quad_pm(trig_type)[1 - 1]
            quad_text = '第一象限'
        elif text.find('第二象限') >= 0:
            pm = jiao.trig_f_quad_pm(trig_type)[2 - 1]
            quad_text = '第二象限'
        elif text.find('第三象限') >= 0:
            pm = jiao.trig_f_quad_pm(trig_type)[3 - 1]
            quad_text = '第三象限'
        elif text.find('第四象限') >= 0:
            pm = jiao.trig_f_quad_pm(trig_type)[4 - 1]
            quad_text = '第三象限'
        else:
            pm = None
        if not pm:
            vs_print = ''
            for v in t_vs:
                vs_print += new_latex(v) + ' |'
            vs_print = vs_print[:-1]
            vs_print = vs_print.replace('|', '和')
            self.steps.append(['\\therefore ', '%s的值为 %s' % (new_latex(t_f), vs_print)])
        else:
            t_vs = list(filter(lambda v1: v1 * pm > 0, t_vs))
            t_v = t_vs[0]
            self.steps.append(['并且 %s' % new_latex(list(trig_arg.free_symbols)[0]), '在' + quad_text])
            self.steps.append([r'\therefore ', '%s = %s' % (new_latex(t_f), new_latex(t_v))])
            self.output.append(BaseNumber(d[t_k]))
        self.label.add('同角三角函数间基本关系')
        return self


# 由sina,cosa，tana的正负，判断a所在的象限
class SanJiaoHanShu005(BaseFunction):
    @staticmethod
    def trig_stand_ineq(ineq):
        """
        标准化三角函数不等式 左边为三角函数，右边为常数
        :param ineq:
        :return:
        """
        l, o, r = ineq.sympify()
        f = l - r
        c = su.trig_coeff(f)
        n_l = l / c
        o = co.reverse_ineq_op(o) if c < 0 else o
        return BaseIneq([n_l, o, 0])

    @staticmethod
    def trig_ineq_quad(trig_ineq):
        std_ineq = SanJiaoHanShu005.trig_stand_ineq(trig_ineq)
        l, o, r = std_ineq.sympify()
        qs = jiao.trig_f_quad_pm(str(type(l)))
        qs = map(lambda q: (q[0] + 1, q[1]), enumerate(qs))
        qs = filter(lambda q: solveset(str(q[1]) + o + str(r), domain=S.Reals), qs)
        qs = map(lambda q: q[0], qs)
        return FiniteSet(*qs)

    def solver(self, *args):
        ineqs = args[0].sympify()
        l1, o, r1 = ineqs[0].sympify()
        f1 = l1 - r1
        trig_s = list(f1.free_symbols)[0]
        intls = map(lambda ineq: SanJiaoHanShu005.trig_ineq_quad(BaseIneq(ineq)), ineqs)
        qds = list(co.intervals_intersect(intls))
        self.steps.append(['角 %s 所在象限为' % new_latex(trig_s), '第 %s 象限' % qds[0]])
        return self


# 根据角所在的象限给出象限的取值范围
class SanJiaoHanShu006(BaseFunction):
    def solver(self, *args):
        variable = args[0].sympify()
        text = args[1]
        var_intl = None
        quad = 1
        if text.find('第一') >= 0:
            var_intl = BaseSymbolValue({str(variable): (0, pi / 2)})
            quad = 1
        elif text.find('第二') >= 0:
            var_intl = BaseSymbolValue({str(variable): (pi / 2, pi)})
            quad = 2
        elif text.find('第三') >= 0:
            var_intl = BaseSymbolValue({str(variable): (pi, 3 * pi / 2)})
            quad = 3
        elif text.find('第四') >= 0:
            var_intl = BaseSymbolValue({str(variable): (3 * pi / 2, 2 * pi)})
            quad = 4
        # self.output.append(var_intl)
        self.output.append(var_intl)
        self.output.append(BaseSymbolValue({str(variable) + '_quadrant': quad}))
        # self.known['quad'] = var_intl
        return self


# 三角函数值域问题
# 函数y=sinx+|sinx|的值域是().
class SanJiaoHanShu007(BaseFunction):
    trig_ps = [r'sin\(.*?\)', r'cos\(.*?\)', r'tan\(.*?\)']

    @staticmethod
    def trig_subs(f):
        """
        三角函数替换 sin:A,cos:C, tan:T
        :param f:
        :return:
        """
        sin_p = r'sin\(.*?\)'  # A
        f = su.f_subs(sin_p, f, 'A')
        cos_p = r'cos\(.*?\)'  # C
        f = su.f_subs(cos_p, f, 'C')
        tan_p = r'tan\(.*?\)'  # T
        f = su.f_subs(tan_p, f, 'T')
        return f

    @staticmethod
    def same_trig_type(f):
        """
        相同的三角函数类型
        :param f:
        :return:
        """
        sin_p = r'sin\(.*?\)'  # A
        cos_p = r'cos\(.*?\)'  # C
        tan_p = r'tan\(.*?\)'  # T
        trig_ps = filter(lambda sp: re.findall(sp, str(f)), [sin_p, cos_p, tan_p])
        if len(trig_ps) == 1:
            return True
        else:
            return False

    @staticmethod
    def only_single_trig(f):
        """
        是否只含有 sin 或者 cos 三角函数的表达式 并且 三角函数里面的式子也相等
        :param f: 三角函数
        :return:
        """
        sin_p = r'sin\(.*?\)'  # A
        cos_p = r'cos\(.*?\)'  # C
        tan_p = r'tan\(.*?\)'  # T
        trig_ps = list(filter(lambda sp: re.findall(sp, str(f)), [sin_p, cos_p, tan_p]))
        if len(trig_ps) == 1:
            trig_p = trig_ps[0]
            args = []
            for t in re.findall(trig_p, str(f)):
                tf = sympify(t).args[0]
                args.append(str(sympify(tf)))
            if len(args) != len(set(args)):
                return True
            else:
                return False
        else:
            return False

    @staticmethod
    def try_simp(f):
        """
        穷举化简. 最终化简成只含有一个函数的形式,或者转变成 a*cos(x) + b*sin(x) 然后使用辅助角公式sqrt(a**2 + b**2)*sin(x + c)。
        :param f:
        :return:
        """
        tmp_f = f
        try_count = 0
        contiued = True
        while try_count <= 100 and contiued:
            mons, const = co.symoms_and_const(tmp_f)
            tmp_mons_list = []
            for m in mons:
                tmp_mons_list.append()

    def solver(self, *args):
        y_symbol, f = args[0].sympify()
        self.steps.append(['%s = %s ' % (new_latex(y_symbol), new_latex(f)), ''])
        ef = expand_trig(f)
        if f != ef:
            self.steps.append(['', ' = ' + new_latex(ef)])
        if co.absed_mo(ef):  # 如果含有绝对值
            abs_p = r'Abs\(.*?\)'
            abs_term = re.findall(abs_p, str(ef))[0]
            abs_term = 'Abs(sin(x))'
            abs_arg = sympify(abs_term).args[0]
            seg_fs = [(trigsimp(ef.subs(abs_term, abs_arg)), solveset(abs_arg > 0, domain=S.Reals)),
                      (trigsimp(ef.subs(abs_term, -abs_arg)), solveset(abs_arg < 0, domain=S.Reals))]
            seg_func = su.to_seg_func(seg_fs)
            seg_print = seg_func.printing()
            self.steps.append([r'\therefore ', seg_print])
            seg1 = SanJiaoHanShu007.trig_subs(seg_fs[0][0])
            symb = list(seg1.free_symbols)[0]
            seg1_i = co.func_domain(seg1, {str(symb): Interval(-1, 1)})
            seg1_i = FiniteSet(seg1_i) if seg1_i.is_real else seg1_i
            seg2 = SanJiaoHanShu007.trig_subs(seg_fs[1][0])
            seg2_i = co.func_domain(seg2, {str(symb): Interval(-1, 1)})
            seg2_i = FiniteSet(seg2_i) if seg2_i.is_real else seg2_i
            ri = co.intervals_union([seg1_i, seg2_i])
        elif SanJiaoHanShu007.only_single_trig(ef):  # 如果只含有一个三角函数, 则不需要化简
            sf = SanJiaoHanShu007.trig_subs(ef)
            trig_p = list(filter(lambda tp: re.findall(tp, str(ef)), SanJiaoHanShu007.trig_ps))[0]
            symb = list(sf.free_symbols)[0]
            trig_r = re.findall(trig_p, str(ef))[0]
            i = Interval(-1, 1)
            if degree(sf) == 2:  # 如果是二次
                sf, _ = co.top_point_expr(sf, symb)
                pf = sf.subs(symb, trig_r)
                self.steps.append(['  =', new_latex(pf)])
                ri = su.quad_func_domain(sf, i, symb)
            elif su.fraced(sf):  # 如果是分式
                sf = co.frac_simp(sf)
                pf = sf.subs(symb, trig_r)
                self.steps.append(['  = ', new_latex(pf)])
                ri = co.func_domain(sf, {str(symb): Interval(-1, 1)})
        # elif SanJiaoHanShu007.same_trig_type(f):  # 如果只含有三角函数类型
        #     f = expand_trig(f)
        #     if SanJiaoHanShu007.only_single_trig(f):
        #         sf = SanJiaoHanShu007.trig_subs(f)
        #         symb = list(sf.free_symbols)[0]
        #         i = Interval(-1, 1)
        #         if degree(sf) == 2:  # 如果是二次
        #             trig_p = filter(lambda tp: re.findall(tp, str(f)), SanJiaoHanShu007.trig_ps)[0]
        #             sf, _ = co.top_point_expr(sf, symb)
        #             trig_r = re.findall(trig_p, str(f))[0]
        #             pf = sf.subs(symb, trig_r)
        #             self.steps.append(['%s = %s' % (latex(y_symbol), latex(f)), ' = %s' % latex(pf)])
        #             ri = su.quad_func_domain(sf, i, symb)
        else:
            from mathsolver.functions.sanjiao.huajian import trig_simplify
            # f_simp, simp_steps = su.trig_simp(f)
            f_simp = trig_simplify(f)
            self.steps.append([r'\because ' + new_latex(y_symbol), ' = ' + new_latex(f_simp)])
            sf = SanJiaoHanShu007.trig_subs(f_simp)
            d = {'A': Interval(-1, 1), 'C': Interval(-1, 1), 'T': Interval(-1, 1)}
            ri = co.func_domain(sf, d)
        self.steps.append(['\\therefore ', '则函数的值域是：' + new_latex(ri)])
        self.output.append(co.to_base_interval(ri))
        self.label.add('三角函数的值域')
        return self


# 若α为锐角 输出区间
class SanJiaoHanShu008(BaseFunction):
    def solver(self, *args):
        v = args[0].sympify()
        self.output.append(BaseSymbolValue({str(v): [0, pi]}))
        return self


if __name__ == '__main__':
    pass
